home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************************
- * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE *
- * is provided to you without charge, and with no warranty. You may give *
- * away copies of JOVE, including sources, provided that this notice is *
- * included in all the files. *
- ***************************************************************************/
-
- #include "jove.h"
- #include "termcap.h"
- #include "ctype.h"
- #include "chars.h"
- #include "disp.h"
- #include "fp.h"
- #include "scandir.h"
-
- #include <signal.h>
-
- #ifdef MAC
- # include "mac.h"
- #else /* !MAC */
- # ifdef STDARGS
- # include <stdarg.h>
- # else
- # include <varargs.h>
- # endif
- # ifdef F_COMPLETION
- # include <stat.h>
- # endif
- #endif /* !MAC */
-
- int AbortChar = CTL('G');
- bool DoEVexpand = NO; /* should we expand evironment variables? */
-
- bool Asking = NO;
- int AskingWidth;
-
- char Minibuf[LBSIZE];
- private Line *CurAskPtr = NULL; /* points at some line in mini-buffer */
- private Buffer *AskBuffer = NULL; /* Askbuffer points to actual structure */
-
- /* The way the mini-buffer works is this: The first line of the mini-buffer
- is where the user does his stuff. The rest of the buffer contains
- strings that the user often wants to use, for instance, file names, or
- common search strings, etc. If he types C-N or C-P while in ask(), we
- bump the point up or down a line and extract the contents (we make sure
- is somewhere in the mini-buffer). */
-
- private Buffer *
- get_minibuf()
- {
- if (AskBuffer) { /* make sure ut still exists */
- register Buffer *b;
-
- for (b = world; b != NULL; b = b->b_next)
- if (b == AskBuffer)
- return b;
- }
- AskBuffer = do_select((Window *)NULL, "*minibuf*");
- AskBuffer->b_type = B_SCRATCH;
- return AskBuffer;
- }
-
- /* Add a string to the mini-buffer. */
-
- void
- minib_add(str, movedown)
- char *str;
- bool movedown;
- {
- register Buffer *saveb = curbuf;
-
- SetBuf(get_minibuf());
- LineInsert(1);
- ins_str(str, NO);
- if (movedown)
- CurAskPtr = curline;
- SetBuf(saveb);
- }
-
- /* look for any substrings of the form $foo in linebuf, and expand
- them according to their value in the environment (if possible) -
- this munges all over curchar and linebuf without giving it a second
- thought (I must be getting lazy in my old age) */
- private void
- EVexpand()
- {
- register int c;
- register char *lp = linebuf,
- *ep;
- char varname[128],
- *vp,
- *lp_start;
- Mark *m = MakeMark(curline, curchar, M_FLOATER);
-
- while ((c = *lp++) != '\0') {
- if (c != '$')
- continue;
- lp_start = lp - 1; /* the $ */
- vp = varname;
- while ((c = *lp++) != '\0') {
- if (!jisword(c))
- break;
- *vp++ = c;
- }
- *vp = '\0';
- /* if we find an env. variable with the right
- name, we insert it in linebuf, and then delete
- the variable name that we're replacing - and
- then we continue in case there are others ... */
- if ((ep = getenv(varname)) != NULL) {
- curchar = lp_start - linebuf;
- ins_str(ep, NO);
- del_char(FORWARD, (int)strlen(varname) + 1, NO);
- lp = linebuf + curchar;
- }
- }
- ToMark(m);
- DelMark(m);
- }
-
- bool InRealAsk = NO;
-
- private char *
- real_ask(delim, d_proc, def, prompt)
- char *delim,
- *def,
- *prompt;
- bool (*d_proc) proto((int));
- {
- jmp_buf savejmp;
- int c,
- prompt_len;
- Buffer *saveb = curbuf;
- volatile int aborted = NO;
- int no_typed = NO;
- data_obj *push_cmd = LastCmd;
- int o_a_v = arg_value(),
- o_i_an_a = is_an_arg();
- #ifdef MAC
- menus_off();
- #endif
-
- if (InRealAsk)
- complain((char *) NULL);
- push_env(savejmp);
- InRealAsk = YES;
- SetBuf(get_minibuf());
- if (!inlist(AskBuffer->b_first, CurAskPtr))
- CurAskPtr = curline;
- prompt_len = strlen(prompt);
- ToFirst(); /* Beginning of buffer. */
- linebuf[0] = '\0';
- modify();
- makedirty(curline);
-
- if (setjmp(mainjmp)) {
- if (InJoverc) { /* this is a kludge */
- aborted = YES;
- goto cleanup;
- }
- }
-
- for (;;) {
- clr_arg_value();
- last_cmd = this_cmd;
- init_strokes();
- cont:
- s_mess("%s%s", prompt, linebuf);
- Asking = YES;
- AskingWidth = curchar + prompt_len;
- c = getch();
-
- if ((c == EOF) || (c != '\0' && strchr(delim, c) != NULL)) {
- if (DoEVexpand)
- EVexpand();
- if (d_proc == (bool(*) proto((int)))NULL || !(*d_proc)(c))
- break;
- } else if (c == AbortChar) {
- message("[Aborted]");
- aborted = YES;
- break;
- } else switch (c) {
- case CTL('N'):
- case CTL('P'):
- if (CurAskPtr != NULL) {
- int n = (c == CTL('P') ? -arg_value() : arg_value());
- CurAskPtr = next_line(CurAskPtr, n);
- if (CurAskPtr == curbuf->b_first && CurAskPtr->l_next != NULL)
- CurAskPtr = CurAskPtr->l_next;
- (void) ltobuf(CurAskPtr, linebuf);
- modify();
- makedirty(curline);
- Eol();
- this_cmd = 0;
- }
- break;
-
- case CTL('R'):
- if (def)
- ins_str(def, NO);
- else
- rbell();
- break;
-
- default:
- dispatch(c);
- break;
- }
- if (curbuf != AskBuffer)
- SetBuf(AskBuffer);
- if (curline != curbuf->b_first) {
- CurAskPtr = curline;
- curline = curbuf->b_first; /* with whatever is in linebuf */
- }
- if (this_cmd == ARG_CMD)
- goto cont;
- }
- cleanup:
- pop_env(savejmp);
-
- LastCmd = push_cmd;
- set_arg_value(o_a_v);
- set_is_an_arg(o_i_an_a);
- no_typed = (linebuf[0] == '\0');
- strcpy(Minibuf, linebuf);
- SetBuf(saveb);
- InRealAsk = Asking = Interactive = NO;
- if (!aborted) {
- if (!charp()) {
- Placur(ILI, 0);
- flushscreen();
- }
- if (no_typed)
- return NULL;
- } else
- complain(mesgbuf);
- return Minibuf;
- }
-
- #ifdef STDARGS
- char *
- ask(char *def, char *fmt,...)
- #else
- /*VARARGS2*/ char *
- ask(def, fmt, va_alist)
- char *def,
- *fmt;
- va_dcl
- #endif
- {
- char prompt[128];
- char *ans;
- va_list ap;
-
- va_init(ap, fmt);
- format(prompt, sizeof prompt, fmt, ap);
- va_end(ap);
- ans = real_ask("\r\n", (bool (*) proto((int))) NULL, def, prompt);
- if (ans == NULL) { /* Typed nothing. */
- if (def == NULL)
- complain("[No default]");
- return def;
- }
- return ans;
- }
-
- #ifdef STDARGS
- char *
- do_ask(char *delim, bool (*d_proc) proto((int)), char *def, const char *fmt,...)
- #else
- /*VARARGS4*/ char *
- do_ask(delim, d_proc, def, fmt, va_alist)
- char *delim,
- *def;
- const char *fmt;
- bool (*d_proc) proto((int));
- va_dcl
- #endif
- {
- char prompt[128];
- va_list ap;
-
- va_init(ap, fmt);
- format(prompt, sizeof prompt, fmt, ap);
- va_end(ap);
- return real_ask(delim, d_proc, def, prompt);
- }
-
- #ifdef STDARGS
- int
- yes_or_no_p(char *fmt, ...)
- #else
- /*VARARGS1*/ int
- yes_or_no_p(fmt, va_alist)
- char *fmt;
- va_dcl
- #endif
- {
- char prompt[128];
- int c;
- va_list ap;
-
- va_init(ap, fmt);
- format(prompt, sizeof prompt, fmt, ap);
- va_end(ap);
- for (;;) {
- message(prompt);
- Asking = YES; /* so redisplay works */
- AskingWidth = strlen(prompt);
- c = getch();
- Asking = NO;
- if (c == AbortChar)
- complain("[Aborted]");
- switch (CharUpcase(c)) {
- case 'Y':
- return YES;
-
- case 'N':
- return NO;
-
- default:
- add_mess("[Type Y or N]");
- SitFor(10);
- }
- }
- /* NOTREACHED */
- }
-
- #ifdef F_COMPLETION
-
- private char *fc_filebase;
- bool DispBadFs = YES; /* display bad file names? */
- # ifndef MSDOS
- char BadExtensions[128] = ".o";
- # else /* MSDOS */
- char BadExtensions[128] = ".obj .exe .com .bak .arc .lib .zoo";
- # endif /* MSDOS */
-
- private int
- bad_extension(name)
- char *name;
- {
- char *ip,
- *bads;
- size_t namelen = strlen(name),
- ext_len;
-
- #ifdef UNIX
- if (strcmp(name, ".")==0 || strcmp(name, "..")==0)
- return YES;
- #endif
- for (ip=bads=BadExtensions; *ip!='\0'; bads = ip+1) {
- if ((ip = strchr(bads, ' ')) == NULL)
- ip = bads + strlen(bads);
- ext_len = ip - bads;
- if (ext_len != 0 && ext_len < namelen &&
- (strncmp(&name[namelen - ext_len], bads, ext_len) == 0))
- return YES;
- }
- return NO;
- }
-
- private int
- f_match(file)
- char *file;
- {
- int len = strlen(fc_filebase);
-
- if (!DispBadFs && bad_extension(file))
- return NO;
-
- return ((len == 0) ||
- #ifdef MSDOS
- (casencmp(file, fc_filebase, strlen(fc_filebase)) == 0)
- #else
- (strncmp(file, fc_filebase, strlen(fc_filebase)) == 0)
- #endif
- );
- }
-
- private int
- isdir(name)
- char *name;
- {
- struct stat stbuf;
- char filebuf[FILESIZE];
-
- PathParse(name, filebuf);
- return ((stat(filebuf, &stbuf) != -1) &&
- (stbuf.st_mode & S_IFDIR) == S_IFDIR);
- }
-
- private void
- fill_in(dir_vec, n)
- register char **dir_vec;
- int n;
- {
- int minmatch = 0,
- numfound = 0,
- lastmatch = -1,
- i,
- the_same = TRUE, /* After filling in, are we the same
- as when we were called? */
- is_ntdir; /* Is Newly Typed Directory name */
-
- for (i = 0; i < n; i++) {
- /* if it's no, then we have already filtered them out
- in f_match() so there's no point in doing it again */
- if (DispBadFs && bad_extension(dir_vec[i]))
- continue;
- if (numfound)
- minmatch = min(minmatch,
- numcomp(dir_vec[lastmatch], dir_vec[i]));
- else
- minmatch = strlen(dir_vec[i]);
- lastmatch = i;
- numfound += 1;
- }
- /* Ugh. Beware--this is hard to get right in a reasonable
- manner. Please excuse this code--it's past my bedtime. */
- if (numfound == 0) {
- rbell();
- return;
- }
- Eol();
- if (minmatch > (int)strlen(fc_filebase)) {
- the_same = FALSE;
- null_ncpy(fc_filebase, dir_vec[lastmatch], (size_t) minmatch);
- Eol();
- makedirty(curline);
- }
- is_ntdir = ((numfound == 1) &&
- (curchar > 0) &&
- (linebuf[curchar - 1] != '/') &&
- (isdir(linebuf)));
- if (the_same && !is_ntdir) {
- add_mess((n == 1) ? " [Unique]" : " [Ambiguous]");
- SitFor(7);
- }
- if (is_ntdir)
- insert_c('/', 1);
- }
-
- /* called from do_ask() when one of "\r\n ?" is typed. Does the right
- thing, depending on which. */
-
- private bool
- f_complete(c)
- int c;
- {
- char dir[FILESIZE],
- **dir_vec;
- int nentries,
- i;
-
- if (c == CR || c == LF)
- return FALSE; /* tells ask to return now */
- fc_filebase = strrchr(linebuf, '/');
- #if defined(MSDOS) || defined(MiNT)
- if (fc_filebase == NULL) {
- fc_filebase = strrchr(linebuf, '\\');
- if (fc_filebase == NULL)
- fc_filebase = strrchr(linebuf, ':');
- }
- #endif /* MSDOS || MiNT */
- if (fc_filebase != NULL) {
- char tmp[FILESIZE];
-
- fc_filebase += 1;
- null_ncpy(tmp, linebuf, (size_t) (fc_filebase - linebuf));
- if (tmp[0] == '\0')
- strcpy(tmp, "/");
- PathParse(tmp, dir);
- } else {
- fc_filebase = linebuf;
- strcpy(dir, ".");
- }
- if ((nentries = jscandir(dir, &dir_vec, f_match, alphacomp)) == -1) {
- add_mess(" [Unknown directory: %s]", dir);
- SitFor(7);
- return TRUE;
- }
- if (nentries == 0) {
- add_mess(" [No match]");
- SitFor(7);
- } else if (c == ' ' || c == '\t')
- fill_in(dir_vec, nentries);
- else {
- /* we're a '?' */
- int maxlen = 0,
- ncols,
- col,
- lines,
- linespercol;
-
- TOstart("Completion", FALSE); /* false means newline only on request */
- Typeout("(! means file will not be chosen unless typed explicitly)");
- Typeout((char *)NULL);
- Typeout("Possible completions (in %s):", dir);
- Typeout((char *)NULL);
-
- for (i = 0; i < nentries; i++)
- maxlen = max((int)strlen(dir_vec[i]), maxlen);
- maxlen += 4; /* pad each column with at least 4 spaces */
- ncols = (CO - 2) / maxlen;
- linespercol = 1 + (nentries / ncols);
-
- for (lines = 0; lines < linespercol; lines++) {
- for (col = 0; col < ncols; col++) {
- bool isbad;
- int which;
-
- which = (col * linespercol) + lines;
- if (which >= nentries)
- break;
- if (DispBadFs)
- isbad = bad_extension(dir_vec[which]);
- else
- isbad = NO;
- Typeout("%s%-*s", isbad ? "!" : NullStr,
- maxlen - isbad, dir_vec[which]);
- }
- Typeout((char *) NULL);
- }
- TOstop();
- }
- freedir(&dir_vec, nentries);
- return TRUE;
- }
-
- #endif /* F_COMPLETION */
-
- char *
- ask_file(prmt, def, buf)
- const char *prmt;
- char *def,
- *buf;
- {
- char *ans,
- prompt[128],
- *pretty_name = pr_name(def, YES);
-
- if (prmt) {
- strcpy(prompt, prmt);
- } else {
- if (def != NULL && *def != '\0') {
- swritef(prompt, sizeof(prompt), ": %f (default %s) ",
- pretty_name);
- if ((int)strlen(prompt) * 2 >= CO)
- swritef(prompt, sizeof(prompt), ProcFmt);
- } else {
- swritef(prompt, sizeof(prompt), ProcFmt);
- }
- }
- #ifdef F_COMPLETION
- ans = real_ask("\r\n \t?", f_complete, pretty_name, prompt);
- if (ans == NULL && (ans = pretty_name) == NULL)
- complain("[No default file name]");
- #else
- ans = ask(pretty_name, prompt);
- #endif
- PathParse(ans, buf);
-
- return buf;
- }
-